package cn.aws360.boot.system.biz.helper;

import cn.aws360.boot.system.api.constant.enums.MenuTypeEnum;
import cn.aws360.boot.system.biz.domain.SysDept;
import cn.aws360.boot.system.biz.domain.SysMenu;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;

import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author junnan
 */
public class TreeHelper {

    public static List<TreeNode<Integer>> buildDeptTreeNodeList(List<SysDept> sysDeptList) {
        return sysDeptList.stream()
                .sorted(Comparator.comparingInt(SysDept::getSort))
                .map(getDeptNodeFunction()).collect(Collectors.toList());
    }

    public static List<TreeNode<Integer>> buildMenuTreeNodeList(List<SysMenu> sysMenuList) {
        return sysMenuList.stream()
                .sorted(Comparator.comparingInt(SysMenu::getSort))
                .map(getMenuNodeFunction()).collect(Collectors.toList());
    }

    public static List<Tree<Integer>> buildTreeList(List<TreeNode<Integer>> nodeList) {
        return nodeList.stream().map(node -> {
            Tree<Integer> tree = new Tree<>();
            tree.putAll(node.getExtra());
            BeanUtils.copyProperties(node, tree);
            return tree;
        }).collect(Collectors.toList());
    }

    public static JSONObject buildMenuPageJson(List<SysMenu> menuList) {
        JSONArray jsonArray = new JSONArray().fluentAdd(buildHomePage());
        List<Tree<Integer>> treeList = TreeUtil.build(buildMenuTreeNodeList(menuList));
        if (CollUtil.isNotEmpty(treeList)) {
            for (Tree<Integer> tree : treeList) {
                JSONObject treePage = buildTreePage(tree);
                if (ObjectUtil.isNotNull(treePage)) {
                    jsonArray.add(treePage);
                }
            }
        }
        return new JSONObject()
                .fluentPut("pages", new JSONArray().fluentAdd(
                        new JSONObject().fluentPut("children", jsonArray)));
    }

    private static Function<SysDept, TreeNode<Integer>> getDeptNodeFunction() {
        return dept -> {
            TreeNode<Integer> deptNode = new TreeNode<>(dept.getId(), dept.getPid(), dept.getName(), dept.getSort());
            Map<String, Object> extra = new HashMap<>(8);
            extra.put("pid", dept.getPid());
            extra.put("sort", dept.getSort());
            extra.put("ancestors", dept.getAncestors());
            extra.put("updateTime", dept.getUpdateTime());
            deptNode.setExtra(extra);
            return deptNode;
        };
    }

    private static Function<SysMenu, TreeNode<Integer>> getMenuNodeFunction() {
        return menu -> {
            TreeNode<Integer> menuNode = new TreeNode<>(menu.getId(), menu.getPid(), menu.getName(), menu.getSort());
            Map<String, Object> extra = new HashMap<>(8);
            extra.put("pid", menu.getPid());
            extra.put("type", menu.getType());
            extra.put("sort", menu.getSort());
            extra.put("icon", menu.getIcon());
            extra.put("path", menu.getPath());
            extra.put("perm", menu.getPerm());
            extra.put("component", menu.getComponent());
            extra.put("updateTime", menu.getUpdateTime());
            menuNode.setExtra(extra);
            return menuNode;
        };
    }

    private static JSONObject buildTreePage(Tree<Integer> tree) {
        JSONObject pageItem1 = buildPageItem(tree);
        if (ObjectUtil.isNull(pageItem1)) {
            return null;
        }

        if (tree.getChildren() != null && tree.getChildren().size() > 0) {
            JSONArray jsonArray = new JSONArray();
            for (Tree<Integer> child : tree.getChildren()) {
                JSONObject pageItem2 = buildTreePage(child);
                if (ObjectUtil.isNotNull(pageItem2)) {
                    jsonArray.add(pageItem2);
                }
            }
            if (CollUtil.isNotEmpty(jsonArray)) {
                pageItem1.put("children", jsonArray);
            }
        }
        return pageItem1;
    }


    private static JSONObject buildHomePage() {
        return new JSONObject()
                .fluentPut("url", "/home")
                .fluentPut("sort", 0)
                .fluentPut("icon", "iconfont icon-home")
                .fluentPut("label", "主页")
                .fluentPut("schemaApi", "home/index.json")
                .fluentPut("isDefaultPage", true);
    }

    private static JSONObject buildPageItem(Tree<Integer> tree) {
        Integer type = (Integer) tree.get("type");
        if (type.equals(MenuTypeEnum.BUTTON.getValue())) {
            return null;
        }

        JSONObject pageItem = new JSONObject()
                .fluentPut("id", tree.getId())
                .fluentPut("url", tree.get("path"))
                .fluentPut("sort", tree.get("sort"))
                .fluentPut("icon", tree.get("icon"))
                .fluentPut("link", tree.get("link"))
                .fluentPut("label", tree.get("name"));
        Object component = tree.get("component");
        if (ObjectUtil.isNotNull(component)) {
            pageItem.put("schemaApi", component);
        }
        return pageItem;
    }

}
